#include "type.h"
#define NUM_CMD		19

void passThrough(char* cmd);
void sh_cd(char* cmd);
void sh_pwd(char* cmd);

typedef (*cmd_function)(char*);

char commands[NUM_CMD][10] = { "ls", "cd", "pwd", "cat", "more", "cp", "mv",
	"mkdir", "rmdir", "creat", "rm", "chmod", "chown", "lpr", "grep", "ps",
	"man", "ttimer", "hits" };
cmd_function functions[NUM_CMD] = { passThrough, sh_cd, sh_pwd, passThrough,
	passThrough, passThrough, passThrough, passThrough, passThrough,
	passThrough, passThrough, passThrough, passThrough, passThrough,
	passThrough, passThrough, passThrough, passThrough, passThrough };
	
int numPipes(char* cmd)
{
	int count = 0;
	while (*cmd != 0)
	{
		if (*(cmd++) == '|') ++count;
	}
	return count;
}

void executeCmd(char *cmd)
{
	int i;
	for (i = 0; i < NUM_CMD; ++i)
	{
		if (strncmp(cmd, commands[i], strlen(commands[i])) == 0)
		{
			functions[i](cmd);
		}
	}
}

void printHelp()
{
	printf("Available commands:\n");
	printf("---------------------------------------------\n");
	printf("| ls     cd     pwd    cat    more   cp     |\n");
	printf("| mv     mkdir  rmdir  creat  rm     chmod  |\n");
	printf("| chown  lpr    grep   ps     man    ttimer |\n");
	printf("| hits   |      <      >      >>            |\n");
	printf("---------------------------------------------\n");
}

void main(int argc, char* argv[])
{
	int i, pid, status, pipeCount, pipes[2], pipes2[2];
	char cmd[100], *process, *fileRedirect;
	printf("Enter \"help\" for command menu\n");
	
	while (1)
	{
		printf("jrsh >> ");
		gets(cmd);
		
		if (strcmp(cmd, "logout") == 0)
		{
			do_exit(0);
		}
		else if (strcmp(cmd, "help") == 0)
		{
			printHelp();
		}
		else
		{
			pipeCount = numPipes(cmd);
			if (pipeCount > 0)
			{
				int rPid = 0, wPid = 0;
				
				printf("Pipe count: %d\n", pipeCount);
				process = strtok(cmd, "|\n");
				
				// Create the first writer in the chain
				do_pipe(pipes);
				wPid = do_fork();
					
				if (wPid == 0)
				{
					do_dup2(pipes[1], 1);
					executeCmd(process);
				}
				do_close(pipes[1]);
				
				// Process the middle pipes
				for (i = 1; i < pipeCount; ++i)
				{
					do_pipe(pipes2);
					process = strtok(0, "|\n") + 1;
					
					rPid = do_fork();
					if (rPid == 0)
					{
						do_dup2(pipes[0], 0);
						do_dup2(pipes2[1], 1);
						do_exec(process);
					}
					do_close(pipes[0]);
					do_close(pipes2[1]);
					
					pipes[0] = pipes2[0];
				}
				
				// Create the final reader in the chain
				process = strtok(0, "|\n") + 1;
				rPid = do_fork();
				if (rPid == 0)
				{
					do_dup2(pipes[0], 0);
					executeCmd(process);
				}
				else
				{
					// Wait for all children to die
					do_close(pipes[0]);
					for (i = 0; i < pipeCount + 1; ++i)
					{
						pid = do_wait(&status);
					}
				}
			}
			else
			{
				pid = do_fork();
				
				if (pid > 0)
				{
					pid = do_wait(&status);
				}
				else
				{
					// Input redirect
					if (contains('<', cmd))
					{
						process = strtok(cmd, "<");
						fileRedirect = strtok(0, "\n") + 1;
						do_dup2(open(fileRedirect, READ), 0);
						executeCmd(process);
					}
					// Output redirect
					else if (contains('>', cmd))
					{
						process = strtok(cmd, ">");
						fileRedirect = strtok(0, "\n");
						// Append
						if (fileRedirect[0] == '>')
						{
							fileRedirect += 2;
							do_dup2(open(fileRedirect, APPEND), 1);
						}
						// Write
						else
						{
							fileRedirect += 1;
							do_dup2(open(fileRedirect, WRITE), 1);
						}
						executeCmd(process);
					}
					else
					{
						executeCmd(cmd);
					}
				}
			}
		}
	}
}

void passThrough(char* cmd)
{
	do_exec(cmd);
}

void sh_cd(char* cmd)
{
	strtok(cmd, " ");
	do_chdir(strtok(0, " \n\r"));
}

void sh_pwd(char* cmd)
{
	do_pwd();
}
